package com.group525.cloudef.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;

import org.opencv.core.*;
import org.opencv.imgproc.CLAHE;
import org.opencv.imgproc.Imgproc;
import org.springframework.stereotype.Component;

import java.io.FileInputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.io.InputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;

import static org.opencv.highgui.HighGui.*;
import static org.opencv.imgcodecs.Imgcodecs.imread;
import static org.opencv.imgcodecs.Imgcodecs.imwrite;
import static org.opencv.imgproc.Imgproc.*;

@Component
public class PreProcess {

//    /**
//     * 中值滤波
//     * ksize越大，模糊程度越大
//     */
//    public static Mat ZhongZhi(Mat src){
//        Mat dst = new Mat();
//        Imgproc.medianBlur(src, dst, 3);
//        return dst;
//    }

    /**
     * 限制对比度的自适应直方图均衡化（效果好于“普通直方图均衡化”）
     * @param image。输入
     * @return res。输出
     */
    public static Mat HistEqual(Mat image){
        Mat res = image.clone();
        List<Mat> list1 = new ArrayList<>();
        Core.split(res, list1);

        CLAHE clahe = Imgproc.createCLAHE();
        clahe.setClipLimit(4);
        clahe.apply(list1.get(0), list1.get(0));
        Core.merge(list1, res);
        return res;
    }

//    /**
//     * 拉普拉斯算子增强
//     * 用于整体偏暗图像的增强,变亮（太亮了）
//     * @param src。输入
//     * @return dst
//     *
//    public Mat Mat(Mat src) {
//        Mat dst = src.clone();
//        float[] kernel = {0, 0, 0, -1, 5f, -1, 0, 0, 0};
//        Mat kernelMat = new Mat(3, 3, CvType.CV_32FC1);
//        kernelMat.put(0, 0, kernel);
//        Imgproc.filter2D(dst, dst, CvType.CV_8UC3, kernelMat);
//        return dst;
//    }*/
//
//    /**
//     * 对数变换可以将图像的低laplaceEnhance灰度值部分扩展，显示出低灰度部分更多的细节，
//     * 将其高灰度值部分压缩，减少高灰度值部分的细节，从而达到强调图像低灰度部分的目的。
//     * @param src。输入
//     * @return imageResult
//     */
//    public static Mat logEnhance(Mat src) {
//        Mat dst = src.clone();
//        Mat imageResult = new Mat(dst.size(), CvType.CV_32FC3);
//        Core.add(dst, new Scalar(5, 5, 5), dst);
//        dst.convertTo(dst, CvType.CV_32F);
//        Core.log(dst, imageResult);
//        Core.normalize(imageResult, imageResult, 0, 255, Core.NORM_MINMAX);
//        Core.convertScaleAbs(imageResult, imageResult);
//        return imageResult;
//    }
//
//    /**
//     * 伽马变换
//     * power>1==强调高灰度值部分
//     * power<1==强调低灰度值部分
//     * @param src。输入
//     * @return dst
//     */
//    public static Mat gammaEnhance(Mat src) {
//        Mat dst = src.clone();
//        dst.convertTo(dst, CvType.CV_32F);
//
//        Core.pow(dst, 1, dst);
//
//        Core.normalize(dst, dst, 0, 255, Core.NORM_MINMAX);
//        Core.convertScaleAbs(dst, dst);
//        return dst;
//    }
//
//
//    /**
//     * 上采样。（放大）
//     * 默认情况下，输出图像的大小计算为{ Size（src.cols \ * 2，（src.rows \ * 2）}}，但是在任何情况下，都应满足以下条件：
//     * @param src。输入
//     * @return dst。输出
//     */
//    public static Mat imgPyrUp(Mat src) {
//        Mat dst=new Mat();
//        Imgproc.pyrUp(src,dst,new Size(src.cols()*2,src.rows()*2));
//        return dst;
//    }
//
//    /**
//     * 下采样。(缩小)
//     * 默认情况下，输出图像的大小计算为{ Size（（src.cols + 1）/ 2，（src.rows + 1）/ 2）}
//     * @param src。输入
//     * @return dst。输出
//     */
//    public static Mat imgPyrDown(Mat src) {
//        Mat dst=new Mat();
//        Imgproc.pyrDown(src, dst);
//        return dst;
//    }
//
//    /**
//     * 图像归一化
//     * @param src。输入
//     * @return dst。输出
//     *
//     * 1.INTER_LINEAR——线性插值（默认）（用来放大图像，效率高）
//     * 2.INTER_AREA——区域插值（利用像素区域关系的重采样插值）（用来缩小图像）
//     */
//    public static Mat norm(Mat src){
//        Mat dst = new Mat();
//        Size dsize = new Size(src.cols()/2,src.rows()/2);
//        Imgproc.resize(src, dst, dsize, 0, 0, Imgproc.INTER_AREA);
//        return dst;
//    }

    public void testOpencv() throws Exception {
        // 解决awt报错问题
        System.setProperty("java.awt.headless", "false");
        System.out.println(System.getProperty("java.library.path"));
        // 加载动态库
        URL url = ClassLoader.getSystemResource("opencv_java460.dll");
        System.load(url.getPath());

        // 读取图像
        Mat image = imread("./src/main/resources/test.jpg");
        if (image.empty()) {
            throw new Exception("image is empty");
        }

        // 创建输出单通道图像（声明灰度图）
        Mat grayImage = new Mat(image.rows(), image.cols(), CvType.CV_8SC1);
        // 进行图像色彩空间转换（将输入图像转化为灰度图）
        cvtColor(image, grayImage, COLOR_RGB2GRAY);
        // 执行直方图均衡化（传入灰度图）
        Mat out1 = HistEqual(grayImage);

        //imshow("0", grayImage);
        //imshow("1", out1);
        imwrite("./src/main/resources/output.jpg", out1);
        //waitKey(0);
        //destroyAllWindows();
    }

    public boolean download(String fileUrl)/* fileUrl网络资源地址 */
    {
        //图像保存路径
        String savePath = "./src/main/resources/test.jpg";
        try {
            /* 将网络资源地址传给,即赋值给url */
            URL url = new URL(fileUrl);

            /* 此为联系获得网络资源的固定格式用法，以便后面的in变量获得url截取网络资源的输入流 */
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            DataInputStream in = new DataInputStream(connection.getInputStream());

            /* 此处也可用BufferedInputStream与BufferedOutputStream  需要保存的路径*/
            DataOutputStream out = new DataOutputStream(new FileOutputStream(savePath));


            /* 将参数savePath，即将截取的图片的存储在本地地址赋值给out输出流所指定的地址 */
            byte[] buffer = new byte[4096];
            int count = 0;
            while ((count = in.read(buffer)) > 0)/* 将输入流以字节的形式读取并写入buffer中 */
            {
                out.write(buffer, 0, count);
            }
            out.close();/* 后面三行为关闭输入输出流以及网络资源的固定格式 */
            in.close();
            connection.disconnect();
            return true;/* 网络资源截取并存储本地成功返回true */

        } catch (Exception e) {
            System.out.println(e + fileUrl + savePath);
            return false;
        }
    }

    public String upload(Long imageId) {
        // Endpoint
        String endpoint = "oss-cn-shenzhen.aliyuncs.com";
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        String accessKeyId = "LTAI5tET96bxJE7wWVbbQ1uB";
        String accessKeySecret = "ZBH8F4HNIWSEFJy9j4ZpDSptRpCBkz";
        // 填写Bucket名称。
        String bucketName ="medical-image1";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            InputStream inputStream = Files.newInputStream(Paths.get("./src/main/resources/output.jpg"));

            String objectName = imageId +"P.jpg";
            //检查是否有重复命名
            boolean duplicate = ossClient.doesObjectExist(bucketName, objectName);
            //如果有重复，就删除之前的头像
            if(duplicate){
                ossClient.deleteObject(bucketName, objectName);
            }
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, inputStream);
            ossClient.shutdown();

            String url="https://"+bucketName+"."+endpoint+"/"+objectName;
            return url;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //测试用
    public void test() throws Exception {
        // 解决awt报错问题
        System.setProperty("java.awt.headless", "false");
        System.out.println(System.getProperty("java.library.path"));
        // 加载动态库
        URL url = ClassLoader.getSystemResource("opencv_java460.dll");
        System.load(url.getPath());

        // 读取图像
        Mat image = imread("C:/Users/admin/Desktop/Medical-Image/synpic16088.jpeg");
        if (image.empty()) {
            throw new Exception("image is empty");
        }

        // 创建输出单通道图像（声明灰度图）
        Mat grayImage = new Mat(image.rows(), image.cols(), CvType.CV_8SC1);
        // 进行图像色彩空间转换（将输入图像转化为灰度图）
        cvtColor(image, grayImage, COLOR_RGB2GRAY);
        // 执行直方图均衡化（传入灰度图）
        Mat out1 = HistEqual(grayImage);

        imshow("0", grayImage);
        imshow("1", out1);
        //imwrite("./src/main/resources/output.jpg", out1);
        waitKey(0);
        destroyAllWindows();
    }

}
